typedef unsigned char uchar;

//使能端
const int RST=6;
//数据端
const int DAT=5;
//时钟端
const int CLK=4;

char serial_read_complete=false;
char in_setting=false;
String reciveStr="";

//this is a example of DS13302
void setup() {
  Serial.begin(9600);
  //初始化字符串缓冲区长度
  reciveStr.reserve(100);
  pinMode(RST,OUTPUT);
  pinMode(CLK,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  // while(true){//如果用while循环，串口中断会失效
  if(in_setting){
    serialEvent();
    return;
  }
  viewTimeInDs1302();
  // }
  //uno r3支持串口中断，R4不在支持
  serialEvent();
  delay(1000);
}

//显示ds1302里边的时间
void viewTimeInDs1302(){
  uchar years=bcd2DEC(readDs1302Data(0x8d));
  uchar months=bcd2DEC(readDs1302Data(0x89));
  uchar dates=bcd2DEC(readDs1302Data(0x87));
  uchar hours=bcd2DEC(readDs1302Data(0x85));
  uchar minutes=bcd2DEC(readDs1302Data(0x83));
  uchar seconds=bcd2DEC(readDs1302Data(0x81));
  Serial.print(20);
  Serial.print(years);
  Serial.print("-");
  Serial.print(months);
  Serial.print("-");
  Serial.print(dates);
  Serial.print(" ");
  Serial.print(hours);
  Serial.print(":");
  Serial.print(minutes);
  Serial.print(":");
  Serial.print(seconds);
  Serial.println();
}

void writeDs1302Command(char cmd){
  //make sure RST,CLK is Low before begin to send data;
  pinMode(DAT,OUTPUT);
  digitalWrite(RST,LOW);
  digitalWrite(CLK,LOW);
  digitalWrite(RST,HIGH);
  for(char i=0;i<8;i++){
    char sendBit = 0;
    sendBit = cmd & 0x01;
    digitalWrite(CLK,LOW);
    digitalWrite(DAT,sendBit);
    //上升沿写出数据
    digitalWrite(CLK,HIGH);
    cmd=cmd >> 1;
  }
}

uchar readDs1302Data(char cmd){
  //首先写入要读取ds1302的寄存器地址
  writeDs1302Command(cmd);
  //读取数据
  pinMode(DAT,INPUT);
  uchar reciveByte=0;
  for(char i=0;i<8;i++){
    char readBit=0;
    digitalWrite(CLK,LOW);
    readBit=digitalRead(DAT);
    //下降沿读取数据
    digitalWrite(CLK,HIGH);
    if(readBit){
      reciveByte= reciveByte | 0x80;
    }
    if(i!=7){
      reciveByte >>= 1;
    }
  }
  digitalWrite(RST,LOW);
  return reciveByte;
}

void writeDs1302Data(char cmd,uchar data){
  //写入ds1302要写入寄存器的地址
  writeDs1302Command(cmd);
  //十进制转成BCD码
  uchar new_data=dec2BCD(data);
  //写入数据
  for(char i=0;i<8;i++){
    digitalWrite(CLK,LOW);
    char sendBit=new_data & 0x01;
    digitalWrite(DAT,sendBit);
    //上升沿写出数据
    digitalWrite(CLK,HIGH);
    new_data>>=1;
  }
  digitalWrite(RST,LOW);
}

uchar bcd2DEC(uchar bcd){
  uchar num1 = bcd/16;
  uchar num2 = bcd%16;
  return (num1*10+num2);
}

uchar dec2BCD(uchar data){
  uchar num1=data/10;
  uchar num2=data%10;
  return (num1*16+num2);
}

//写入命令和数据
void writeCommandAndData(char cmd,uchar data){
  //关闭写保护
  writeDs1302Data(0x8e,0);
  //写入命令和数据
  writeDs1302Data(cmd,data);
  //开启写保护
  writeDs1302Data(0x8e,0x80);
}

//串口中断，当串口接受到数据过后，改方法会被调用
void serialEvent(){
  while(Serial.available()>0){
    char recive_byte=(char)Serial.read();
    Serial.println(recive_byte);
    if(recive_byte != '\n'){
      reciveStr += recive_byte;
    }else{
      processSerialCommand();
      // serial_read_complete = true;
    }
  }
}

//解析处理指令
void processSerialCommand(){
  in_setting=true;
  Serial.print("Recive command:");
  Serial.print("[");
  Serial.print(reciveStr);
  Serial.print("]");
  Serial.println();

  Serial.println("Analyze Command...");
  if(reciveStr.startsWith("set")){
    String subComd = reciveStr.substring(reciveStr.indexOf(":")+1);
    String parameter=subComd.substring(0,subComd.indexOf(","));
    uchar value=subComd.substring(subComd.indexOf(",")+1).toInt();

    if(parameter.equals("yy")){
      //写入年
      writeCommandAndData(0x8c,value);
      Serial.print("Success setting years to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("mm")){
      //写入月
      writeCommandAndData(0x88,value);
      Serial.print("Success setting months to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("dd")){
      //写入日期
      writeCommandAndData(0x86,value);
      Serial.print("Success setting days to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("wk")){
      //写入星期
      writeCommandAndData(0x8a,value);
      Serial.print("Success setting weeks to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("hh")){
      //写入小时
      writeCommandAndData(0x84,value);
      Serial.print("Success setting hours to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("MM")){
      //写入分
      writeCommandAndData(0x82,value);
      Serial.print("Success setting minutes to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else if(parameter.equals("ss")){
      //写入秒
      writeCommandAndData(0x80,value);
      Serial.print("Success setting seconds to value[");
      Serial.print(value);
      Serial.print("]");
      Serial.println(" into Ds1302!");
      in_setting=false;
    }else{
      Serial.println("Command is illegal!Please input [help] for help.");
    }
  }else if(reciveStr.indexOf("help")!=-1){
    viewHelpMenu();
  }else if(reciveStr.indexOf("exit")!=-1){
    in_setting=false;
    Serial.println("Exist setting.");
  }else{
    Serial.println("Command is illegal!Please input [help] for help,[exit] to back.");
  }
  //命令处理完清空指令
  serial_read_complete = false;
  reciveStr="";

  // //写入年
  // writeDs1302Data(0x8c,24);
  // //写入月份
  // writeDs1302Data(0x88,7);
  // //写入日期
  // writeDs1302Data(0x86,11);
  // //写入星期
  // writeDs1302Data(0x8a,4);
  // //写入分
  // writeDs1302Data(0x82,17);
  // //写入秒
  // writeDs1302Data(0x80,25);
}

//设置帮助菜单
void viewHelpMenu(){
  Serial.println("Command format is begin with [set:],then follow by the parameter you want to set with it's value.");
  Serial.println("Example,if you want to set year [2024] to Ds1302,you can use  this command: set:yy,24");
  Serial.println("The following item is the parameter value can be choice:");
  Serial.println("years:yy");
  Serial.println("months:mm");
  Serial.println("days:dd");
  Serial.println("week:wk");
  Serial.println("hours:hh");
  Serial.println("minutes:MM");
  Serial.println("seconds:ss");
  Serial.println("");
}
